home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / askrunlevel / lilo.c < prev    next >
C/C++ Source or Header  |  1996-05-19  |  22KB  |  881 lines

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <limits.h>
  4. #include "../misc/misc.h"
  5. #include "askrunlevel.h"
  6. #include "../netconf/netconf.h"
  7. #include "../fstab/fstab.h"
  8. #include "../paths.h"
  9. #include "askrunlevel.m"
  10.  
  11. static HELP_FILE help_lilo (HELP_ASKRUN,"lilo");
  12. static CONFIG_FILE f_lilo (ETC_LILO_CONF,help_lilo,CONFIGF_MANAGED);
  13. static CONFIG_FILE f_makefile (USR_SRC_LINUX_MAKEFILE,help_lilo,CONFIGF_NONE);
  14.  
  15. /*
  16.     One configuration
  17. */
  18. class LILO_PARM{
  19. public:
  20.     int ramdisk;    // Size of the ramdisk or no ramdisk
  21.     char read_only;
  22.     SSTRING vga;
  23.     SSTRING root;
  24.     SSTRING append;
  25.     /*~PROTOBEG~ LILO_PARM */
  26. public:
  27.     LILO_PARM (void);
  28.     /*~PROTOEND~ LILO_PARM */
  29. };
  30.  
  31. PUBLIC LILO_PARM::LILO_PARM()
  32. {
  33.     ramdisk = 0;
  34.     read_only = 1;
  35. }
  36.  
  37. /*
  38.     This represent one bootable linux configyration
  39. */
  40. class LILO_CONF: public ARRAY_OBJ{
  41. public:
  42.     char must_be_deleted;    // Is this entry obsoleted
  43.     LILO_PARM parm;
  44.     SSTRING image;
  45.     SSTRING label;
  46.     /*~PROTOBEG~ LILO_CONF */
  47. public:
  48.     LILO_CONF (void);
  49.     /*~PROTOEND~ LILO_CONF */
  50. };
  51.  
  52. PUBLIC LILO_CONF::LILO_CONF()
  53. {
  54.     must_be_deleted = 0;
  55. }
  56.  
  57. class LILO_CONFS: public ARRAY{
  58.     /*~PROTOBEG~ LILO_CONFS */
  59. public:
  60.     LILO_CONF *getitem (int no);
  61.     /*~PROTOEND~ LILO_CONFS */
  62. };
  63.  
  64. PUBLIC LILO_CONF *LILO_CONFS::getitem(int no)
  65. {
  66.     return (LILO_CONF*)ARRAY::getitem(no);
  67. }
  68.  
  69. class LILO_OTHER: public ARRAY_OBJ{
  70. public:
  71.     SSTRING label;
  72.     SSTRING partition;
  73. };
  74. class LILO_OTHERS: public ARRAY{
  75.     /*~PROTOBEG~ LILO_OTHERS */
  76. public:
  77.     LILO_OTHER *getitem (int no);
  78.     /*~PROTOEND~ LILO_OTHERS */
  79. };
  80.  
  81. PUBLIC LILO_OTHER *LILO_OTHERS::getitem(int no)
  82. {
  83.     return (LILO_OTHER*)ARRAY::getitem(no);
  84. }
  85.  
  86. /* #Specification: lilo.conf / how it works
  87.     The lilo.conf file is splitted in two sections. The first
  88.     contain the global or default setting. This section
  89.     act as a default for the rest of the file. This section ends
  90.     with the first "image = " or "other = " statement.
  91.  
  92.     Global settings are:
  93.  
  94.     #
  95.     compact
  96.     delay
  97.     boot = ...
  98.     #
  99.  
  100.     Default setting that can be overriden in the followings
  101.     image= are
  102.  
  103.     #
  104.     ramdisk = x
  105.     read-only
  106.     read-write
  107.     root = ...
  108.     vga = ...
  109.     #
  110. */
  111. struct LILO_CUR{
  112.     LILO_CONF *conf;
  113.     LILO_PARM *parm;
  114.     LILO_OTHER *other;
  115.     int noline;
  116. };
  117. class LILO {
  118.     SSTRING boot;    // On which device to place the boot code
  119.     char compact;    //Special boot mode
  120.     int delay;    // Delay in second or 0 for no delay
  121.     LILO_PARM def;    // Default value
  122.     SSTRING message;    // Path of the message file
  123.     LILO_CONFS confs;
  124.     LILO_OTHERS others;
  125.     char prefix[PATH_MAX];
  126. public:
  127.     char isvalid;    // Tell if the configuration is usable or present
  128.     char isused;    // Is LILO used on this computer
  129.     /*~PROTOBEG~ LILO */
  130. public:
  131.     LILO (void);
  132.     void addkernel (const char *def_src,
  133.          const char *def_name);
  134. private:
  135.     void compute_prefix (void);
  136. public:
  137.     int edit (void);
  138.     LILO_CONF *getconffromlabel (const char *lab);
  139. private:
  140.     void makecfgpath (const char *path, char *realpath);
  141.     void parse_eq (const char *keyw,
  142.          const char *vals,
  143.          LILO_CUR&cur);
  144.     void parse_single (const char *pt, LILO_CUR&cur);
  145. public:
  146.     int save (void);
  147.     void setdefault (void);
  148. private:
  149.     void setupedit (DIALOG&dia);
  150.     void setupparm (DIALOG&dia, LILO_PARM&p);
  151. public:
  152.     int updateif (void);
  153. private:
  154.     int validate (int &nof);
  155. protected:
  156.     void writeparm (FILE *fout,
  157.          LILO_PARM&p,
  158.          int global_parm);
  159. public:
  160.     /*~PROTOEND~ LILO */
  161. };
  162.  
  163.  
  164. /*
  165.     Parse keyword with a value
  166. */
  167. PRIVATE void LILO::parse_eq(
  168.     const char *keyw,
  169.     const char *vals,
  170.     LILO_CUR &cur)
  171. {
  172.     vals = str_skip (vals);
  173.     char word[100];
  174.     str_copyword (word,keyw);
  175.     int numval = atoi(vals);
  176.     if (strcmp(word,"ramdisk")==0){
  177.         cur.parm->ramdisk = numval;
  178.     }else if (strcmp(word,"delay")==0){
  179.         delay = numval;
  180.     }else if (strcmp(word,"boot")==0){
  181.         boot.setfrom (vals);
  182.     }else if (strcmp(word,"vga")==0){
  183.         cur.parm->vga.setfrom (vals);
  184.     }else if (strcmp(word,"message")==0){
  185.         message.setfrom (vals);
  186.     }else if (strcmp(word,"root")==0){
  187.         cur.parm->root.setfrom (vals);
  188.     }else if (strcmp(word,"append")==0){
  189.         cur.parm->append.setfrom (vals);
  190.     }else if (strcmp(word,"label")==0){
  191.         if (cur.conf != NULL){
  192.             cur.conf->label.setfrom (vals);
  193.         }else if (cur.other != NULL){
  194.             cur.other->label.setfrom (vals);
  195.         }else{
  196.             xconf_error ("Misplaced \"label\" statement\n"
  197.                 "in file %s, line %d",f_lilo.getpath()
  198.                 ,cur.noline);
  199.         }
  200.     }else if (strcmp(word,"image")==0){
  201.         cur.conf = new LILO_CONF;
  202.         cur.other = NULL;
  203.         confs.add (cur.conf);
  204.         cur.conf->image.setfrom (vals);
  205.         cur.parm = &cur.conf->parm;
  206.         cur.parm->read_only = def.read_only;
  207.     }else if (strcmp(word,"other")==0){
  208.         cur.other = new LILO_OTHER;
  209.         cur.conf = NULL;
  210.         others.add (cur.other);
  211.         cur.other->partition.setfrom (vals);
  212.     }
  213.         
  214.     
  215. }
  216. /*
  217.     Interpret single word parameter line
  218. */
  219. PRIVATE void LILO::parse_single(const char *pt, LILO_CUR &cur)
  220. {
  221.     char word[100];
  222.     str_copyword (word,pt);
  223.     if (strcmp(word,"compact")==0){
  224.         compact = 1;
  225.     }else if (strcmp(word,"read-only")==0){
  226.         cur.parm->read_only = 1;
  227.     }else if (strcmp(word,"read-write")==0){
  228.         cur.parm->read_only = 0;
  229.     }
  230. }
  231.  
  232.  
  233. PRIVATE void LILO::compute_prefix()
  234. {
  235.     /* #Specification: lilo / moving lilo.conf
  236.         Linuxconf check carefully the path of the configuration
  237.         file (normally /etc/lilo.conf but changeable by the
  238.         user).
  239.  
  240.         We assume that the path of the /boot/map is fairly
  241.         fixed. The only option used with lilo is -r (by
  242.         linuxconf at least), so lilo.conf is somewhere in
  243.         a "etc" directory and the file "map" is somewhere
  244.         in a "boot" directory right near this "etc".
  245.     */
  246.     const char *path = f_lilo.getpath();
  247.     static char stdconf[]= ETC_LILO_CONF;
  248.     if (strcmp (path,stdconf)==0){
  249.         prefix[0] = '\0';
  250.     }else{
  251.         int len = strlen(stdconf);
  252.         int newlen = strlen(path);
  253.         int offset = newlen - len;
  254.         if (newlen < len
  255.             || strcmp(path+offset,stdconf)!=0){
  256.             xconf_error (MSG_U(E_IVLDPATH
  257.                 ,"Invalid path of lilo.conf: %s\n"
  258.                   "expected something at least as long\n"
  259.                   "as %s\n"
  260.                   "and ending with %s")
  261.                 ,path,stdconf,stdconf);
  262.             isvalid = 0;
  263.         }else{
  264.             strncpy (prefix,path,offset);
  265.             prefix[offset] = '\0';
  266.         }
  267.     }
  268. }
  269.  
  270. static char LILOCFG[]="lilo";
  271. static char ISUSED[]="isused";
  272.  
  273. /*
  274.     Load and parse the /etc/lilo.conf configuration file
  275. */
  276. PUBLIC LILO::LILO()
  277. {
  278.     isvalid = 0;
  279.     compact = 0;
  280.     delay = 0;
  281.     /* #Specification: lilo / disabling allowed
  282.         As a default, linuxconf assume lilo is used to
  283.         boot this computer. A check box allows the admin
  284.         to turn lilo off. Linuxconf won't bother the check
  285.         lilo further.
  286.     */
  287.     isused = linuxconf_getvalnum (LILOCFG,ISUSED,1);
  288.     FILE *fin = f_lilo.fopen ("r");
  289.     if (fin != NULL){
  290.         char buf[1000];
  291.         LILO_CUR cur;
  292.         cur.parm = &def;
  293.         cur.conf = NULL;
  294.         cur.other = NULL;
  295.         cur.noline = 0;
  296.         /* #Specification: /etc/lilo.conf / comments
  297.             Comments are not preserved when editing lilo.conf
  298.         */
  299.         isvalid = 1;
  300.         while (fgets_strip(buf,sizeof(buf)-1,fin,&cur.noline)!=NULL){
  301.             strip_end (buf);
  302.             char *pt = str_skip (buf);
  303.             if (*pt != '#' && *pt != '\0'){
  304.                 char *pteq = strchr(pt,'=');
  305.                 if (pteq != NULL){
  306.                     *pteq++ = '\0';
  307.                     parse_eq (pt,pteq,cur);
  308.                 }else{
  309.                     parse_single(pt,cur);
  310.                 }
  311.             }
  312.         }
  313.         fclose (fin);
  314.     }
  315.     compute_prefix();
  316. }
  317.  
  318.  
  319. /*
  320.     Locate one setup from its label
  321. */
  322. PUBLIC LILO_CONF *LILO::getconffromlabel (const char *lab)
  323. {
  324.     LILO_CONF *ret = NULL;
  325.     for (int i=0; i<confs.getnb(); i++){
  326.         LILO_CONF *c = confs.getitem(i);
  327.         if (c->label.cmp(lab)==0){
  328.             ret = c;
  329.             break;
  330.         }
  331.     }
  332.     return ret;
  333. }
  334.  
  335. /*
  336.     Build a path using a path relative to the /etc/lilo.conf file.
  337. */
  338. PRIVATE void LILO::makecfgpath(const char *path, char *realpath)
  339. {
  340.     if (prefix[0] == '\0'){
  341.         strcpy (realpath,path);
  342.     }else{
  343.         strcpy (realpath,prefix);
  344.         strcat (realpath,path);
  345.     }
  346. }
  347.  
  348. static void writeif (FILE *fout, SSTRING &s, const char *keyw)
  349. {
  350.     if (!s.is_empty()) fprintf (fout,"  %s = %s\n",keyw,s.get());
  351.  
  352. }
  353.  
  354. PROTECTED void LILO::writeparm(
  355.     FILE *fout,
  356.     LILO_PARM &p,
  357.     int global_parm)    // Is p LILO::parm or
  358.                 // one of the LILO_CONF::parm ?
  359. {
  360.     /* #Specification: lilo / writing lilo.conf / normalising
  361.         linuxconf is not writing back lilo.conf in the same
  362.         way it was read. It is somewhat normalising it.
  363.         If for example, one setup has the same definitions
  364.         than the default setup, the definition are not repeated.
  365.         This feature is transparent to the user though. It make
  366.         the file lilo.conf smaller and easier to read manually.
  367.     */
  368.     if (global_parm || p.ramdisk != def.ramdisk){
  369.         fprintf (fout,"  ramdisk = %d\n",p.ramdisk);
  370.     }
  371.     if (p.vga.is_empty()){
  372.         if (global_parm) fputs ("  vga = normal\n",fout);
  373.     }else{
  374.         fprintf (fout,"  vga = %s\n",p.vga.get());
  375.     }
  376.     writeif (fout,p.append,"append");
  377.     if (global_parm || def.root.is_empty()){
  378.         writeif (fout,p.root,"root");
  379.     }else if (!p.root.is_empty()
  380.         && p.root.cmp(def.root)!=0){
  381.         writeif (fout,p.root,"root");
  382.     }
  383.     if (global_parm || p.read_only != def.read_only){
  384.         fputs (p.read_only ? "  read-only\n" : "  read-write\n"
  385.             ,fout);
  386.     }
  387. }
  388. /*
  389.     Write back the /etc/lilo.conf file.
  390.     Return -1 if any error.
  391. */
  392. PUBLIC int LILO::save()
  393. {
  394.     int ret = -1;
  395.     FILE *fout = f_lilo.fopen ("w");
  396.     if (fout != NULL){
  397.         fprintf (fout,"boot = %s\n",boot.get());
  398.         if (delay != 0) fprintf (fout,"delay = %d\n",delay);
  399.         if (compact) fprintf (fout,"compact\n");
  400.         writeif (fout,message,"message");
  401.         writeparm (fout,def,1);
  402.         int i;
  403.         for (i=0; i<confs.getnb(); i++){
  404.             LILO_CONF *c = confs.getitem(i);
  405.             if (!c->image.is_empty() && !c->must_be_deleted){
  406.                 fprintf (fout,"image = %s\n",c->image.get());
  407.                 fprintf (fout,"  label = %s\n",c->label.get());
  408.                 writeparm (fout,c->parm,0);
  409.             }
  410.         }
  411.         for (i=0; i<others.getnb(); i++){
  412.             LILO_OTHER *c = others.getitem(i);
  413.             if (!c->partition.is_empty()){
  414.                 fprintf (fout,"other = %s\n"
  415.                     ,c->partition.get());
  416.                 fprintf (fout,"  label = %s\n"
  417.                     ,c->label.get());
  418.             }
  419.         }
  420.         ret = fclose (fout);
  421.         linuxconf_replace (LILOCFG,ISUSED,isused);
  422.         linuxconf_save();
  423.     }
  424.     return ret;
  425. }
  426. static void lilo_setpart (FIELD_COMBO *comb)
  427. {
  428.     PARTITIONS *parts = partition_load();
  429.     for (int i=0; i<parts->getnb(); i++){
  430.         PARTITION *p = parts->getitem(i);
  431.         char str[80];
  432.         p->formatinfo (str);
  433.         comb->addopt(p->getdevice(),str);
  434.     }
  435. }
  436.  
  437. /*
  438.     Dispose the parameter of a configuration or the default ones.
  439. */
  440. PRIVATE void LILO::setupparm (DIALOG &dia, LILO_PARM &p)
  441. {
  442.     FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_ROOTPART,"root partition")
  443.         ,p.root);
  444.     lilo_setpart (comb);
  445.     dia.newf_num (MSG_U(F_RAMSIZE,"Ramdisk size"),p.ramdisk);
  446.     dia.newf_chk (MSG_U(F_BOOTMODE,"boot mode"),p.read_only,"Read only");
  447.     comb = dia.newf_combo (MSG_U(F_VGA,"VGA mode"),p.vga);
  448.     comb->addopt (MSG_U(F_NORMAL,"normal"),MSG_U(F_STD8025,"standard 80x25"));
  449.     dia.newf_str (MSG_U(F_BOOTOPT,"Boot options"),p.append);
  450. }
  451.  
  452. /*
  453.     Dispose the dialog
  454. */
  455. PRIVATE void LILO::setupedit (DIALOG &dia)
  456. {
  457.     dia.newf_chk ("",isused,MSG_U(F_LILOUSED
  458.         ,"LILO is used to boot this system"));
  459.     FSTAB fstab;
  460.     FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_INSTBOOT
  461.         ,"Install boot sector on"),boot);
  462.     comb->addopt (fstab.getrootdev(),MSG_U(F_BOOTREC
  463.         ,"boot record of the current root partition"));
  464.     comb->addopt ("/dev/hda",MSG_U(F_MASTERIDE
  465.         ,"Master boot record on IDE systems"));
  466.     comb->addopt ("/dev/sda",MSG_U(F_MASTERSCSI
  467.         ,"Master boot record on SCSI systems"));
  468.     comb->addopt (MSG_U(F_FD0,"/dev/fd0"),"");
  469.     lilo_setpart (comb);
  470.     dia.newf_chk (MSG_U(F_BIOSMODE,"Bios boot mode"),compact,"Compact");
  471.     dia.newf_num (MSG_U(F_BOOTDELAY,"Boot delay in 1/10 of seconds"),delay);
  472.     dia.newf_str (MSG_U(F_MSGFILE,"Message file(opt)"),message);
  473.     dia.newf_title ("",MSG_U(T_DEFAULTS,"Defaults"));
  474.     setupparm (dia,def);
  475.     /* #Specification: LILO editing / empty slots
  476.         Linuxconf always add two more LILO_CONF records
  477.         and two LILO_OTHER records, so the user is able
  478.         to fill new one. Ideally a special buttons would
  479.         be needed.
  480.     */
  481.     int i;
  482.     for (i=0; i<2; i++){
  483.         LILO_CONF *conf = new LILO_CONF;
  484.         conf->parm.read_only = def.read_only;
  485.         confs.add (conf);
  486.     }
  487.     for (i=0; i<2; i++)others.add (new LILO_OTHER);
  488.     dia.newf_title ("",MSG_U(T_SETUPS,"Linux setups"));
  489.     for (i=0; i<confs.getnb(); i++){
  490.         if (i == 0){
  491.             dia.newf_title ("",MSG_U(F_DEFBOOT,"Defaut Linux boot"));
  492.         }else{
  493.             dia.newf_title ("","-");
  494.         }
  495.         LILO_CONF *c = confs.getitem(i);
  496.         dia.newf_chk ("",c->must_be_deleted
  497.             ,MSG_U(F_DELCFG,"Delete this configuration"));
  498.         dia.newf_str (MSG_U(F_LABEL,"Label"),c->label);
  499.         dia.newf_str (MSG_U(F_KERNELIMAGE,"Kernel image file"),c->image);
  500.         setupparm (dia,c->parm);
  501.     }
  502.     dia.newf_title ("",MSG_U(F_OTHEROS,"Other operating systems"));
  503.     for (i=0; i<others.getnb(); i++){
  504.         if (i != 0) dia.newf_title ("","-");
  505.         LILO_OTHER *c = others.getitem(i);
  506.         dia.newf_str (MSG_R(F_LABEL),c->label);
  507.         FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_PARTBOOT
  508.              ,"partition to boot")
  509.             ,c->partition);
  510.         lilo_setpart (comb);
  511.     }
  512. }
  513.  
  514. static int validate_parm(
  515.     LILO_PARM &p,
  516.     int complain_if_empty)
  517. {
  518.     PARTITIONS *parts = partition_load();
  519.     int ret = -1;
  520.     if (!p.root.is_empty()){
  521.         const char *pr = p.root.get();
  522.         PARTITION *e = parts->getitem(pr);
  523.         if (strncmp(pr,"/dev/fd",7)==0){
  524.             ret = 0;
  525.         }else if (e == NULL || !e->islinux()){
  526.             xconf_error (MSG_U(E_IVLDPART,"Partition %s is either invalid\n"
  527.                 "or not a linux partition\n"),pr);
  528.         }else{
  529.             ret = 0;
  530.         }
  531.     }else if(complain_if_empty){
  532.         xconf_error (MSG_U(E_ROOTPNEED,"You must specify the root partition"));
  533.     }else{
  534.         ret = 0;
  535.     }
  536.     return ret;
  537. }
  538.  
  539.  
  540. /*
  541.     Sanity check of the complete configuration
  542.     Return -1 if any error.
  543.     nof will contain the number of the faulty field.
  544. */
  545. PRIVATE int LILO::validate(int &nof)
  546. {
  547.     validate_parm (def,0);
  548.     int i;
  549.     int ret = 0;
  550.     PARTITIONS *parts = partition_load();
  551.     if (boot.cmp("/dev/fd0")!=0
  552.         && boot.cmp("/dev/hda")!=0
  553.         && boot.cmp("/dev/sda")!=0
  554.         && parts->getitem(boot.get())==NULL){
  555.         xconf_error (MSG_U(E_IVLSECTOR
  556.             ,"Invalid partition or device for boot sector\n"
  557.              "installation"));
  558.         nof = 0;
  559.         ret = -1;
  560.     }
  561.     if (ret == 0){
  562.         for (i=0; i<confs.getnb() && ret == 0; i++){
  563.             LILO_CONF *c = confs.getitem(i);
  564.             if (!c->image.is_empty() && !c->must_be_deleted){
  565.                 ret = validate_parm (c->parm
  566.                     ,def.root.is_empty());
  567.                 // This computation is completly dependant on
  568.                 // the dialog layout.
  569.                 if (ret != 0) nof = i*8 + 13;
  570.             }
  571.         }
  572.     }
  573.     return ret;
  574. }
  575.  
  576.  
  577. PUBLIC int LILO::edit()
  578. {
  579.     int nof = 0;
  580.     int ret = -1;
  581.     while (1){
  582.         DIALOG dia;
  583.         setupedit (dia);
  584.         MENU_STATUS code = dia.edit (
  585.             MSG_U(T_LILOCONF,"LInux LOader configuration")
  586.             ,MSG_U(I_LILOCONF,"You are allowed to specify\n"
  587.              "-how it boots\n"
  588.              "-where (which partition)\n"
  589.              "-and what (LILO can boot almost any OS)")
  590.             ,help_lilo
  591.             ,nof
  592.             ,MENUBUT_ACCEPT|MENUBUT_CANCEL|MENUBUT_INS);
  593.         if (code == MENU_ESCAPE || code == MENU_CANCEL){
  594.             break;
  595.         }else if (code == MENU_INS){
  596.             confs.insert (0,new LILO_CONF);
  597.         }else if (code == MENU_ACCEPT){
  598.             if (validate(nof)!=-1){
  599.                 ret = save();
  600.                 break;
  601.             }
  602.         }
  603.     }
  604.     return ret;
  605. }
  606.  
  607. int lilo_edit ()
  608. {
  609.     LILO lilo;
  610.     int ret = lilo.edit();
  611.     if (ret == 0) lilo.updateif();
  612.     return ret;
  613. }
  614.  
  615. /*
  616.     Exec /sbin/lilo if needed.
  617.     Return 0 if not need, or -1 if any error.
  618. */
  619. PUBLIC int LILO::updateif()
  620. {
  621.     char path[PATH_MAX];
  622.     makecfgpath ("/boot/map",path);
  623.     long confdate = f_lilo.getdate ();
  624.     long mapdate = file_date (path);
  625.     int ret = 0;
  626.     /* #Specification: lilo / update needed if
  627.         If the file /etc/lilo.conf is newer than /boot/map
  628.         then the command lilo must be executed.
  629.  
  630.         kernel files are also checked. If they are newer than
  631.         /boot/map, lilo has to be executed as this situation
  632.         may yield a non bootable system. Simply copying over
  633.         a kernel image may create a mismatch in /boot/map
  634.         and the actual layout of the kernel on the disk
  635.     */
  636.     int needed = 0;
  637.     if (confdate > mapdate){
  638.         needed = 1;
  639.     }else{
  640.         // Check all kernel to see if they are newer
  641.         // Failing
  642.         for (int i=0; i<confs.getnb(); i++){
  643.             LILO_CONF *c = confs.getitem(i);
  644.             makecfgpath (c->image.get(),path);
  645.             long image_date = file_date (path);
  646.             if (image_date > mapdate){
  647.                 needed = 1;
  648.                 break;
  649.             }
  650.         }
  651.  
  652.     }
  653.     if (needed){
  654.         char buf[PATH_MAX];
  655.         buf[0] = '\0';
  656.         if (prefix[0] != '\0')    sprintf (buf,"-r %s",prefix);
  657.         if (simul_ison()
  658.             || xconf_yesno(MSG_U(T_ACTLILO,"Activating LILO configuration")
  659.                 ,MSG_U(Q_ACTLILO,"Activating LILO change the way your\n"
  660.                  "machine is booting.\n"
  661.                  "Do I activate the configuration ?")
  662.                 ,help_lilo)==MENU_YES){
  663.             ret = netconf_system_if ("lilo",buf);
  664.         }else{
  665.             ret = 0;
  666.         }
  667.     }
  668.     return ret;
  669. }
  670.  
  671.  
  672. /*
  673.     Check if the lilo command must be executed
  674. */
  675. int lilo_update ()
  676. {
  677.     int ret = 0;
  678.     DAEMON *dae = daemon_find("lilo");
  679.     if (dae != NULL && dae->is_managed()){
  680.         LILO lilo;
  681.         if (lilo.isvalid && lilo.isused) ret = lilo.updateif();
  682.     }
  683.     return ret;
  684. }
  685.  
  686. /*
  687.     Add a new kernel to the current configuration
  688. */
  689. PUBLIC void LILO::addkernel(
  690.     const char *def_src,    // Default path for the kernel
  691.     const char *def_name)    // Default name for kernel file
  692. {
  693.     DIALOG dia;
  694.     SSTRING kernel_src (def_src);
  695.     SSTRING kernel_dst;
  696.     SSTRING label;
  697.     char install = 0;
  698.     dia.newf_str (MSG_R(F_KERNELIMAGE),kernel_src);
  699.     dia.newf_radio (MSG_U(F_HOWBOOT,"How it boots"),install,0
  700.         ,MSG_U(F_NEWDEFAULT,"new default bootable setup"));
  701.     dia.newf_radio (" ",install,1
  702.         ,MSG_U(F_REPLCUR,"replace the current bootable setup"));
  703.     dia.newf_radio (" ",install,2,MSG_U(F_SELSETUP,"selectable setup"));
  704.     dia.newf_str (MSG_R(F_LABEL),label);
  705.     if (prefix != '\0' ){
  706.         kernel_dst.setfrom (prefix);
  707.         kernel_dst.append ("/");
  708.     }
  709.     kernel_dst.append (def_name);
  710.     dia.newf_str (MSG_U(F_WHERETOCOPY,"Where to copy the kernel file")
  711.         ,kernel_dst);
  712.     LILO_PARM newparm = def;
  713.     dia.newf_title ("",MSG_U(F_OPTIONS,"Options"));
  714.     setupparm (dia,newparm);
  715.     int nof = 0;
  716.     while (1){
  717.         int len_prefix = strlen(prefix);
  718.         MENU_STATUS code = dia.edit (
  719.             MSG_U(T_ADDINGKERN,"Adding a new kernel to LILO")
  720.             ,MSG_U(I_ADDINGKERN
  721.              ,"You have already a working LILO\n"
  722.               "and you want to upgrade your kernel")
  723.             ,help_lilo
  724.             ,nof);
  725.         if (code == MENU_CANCEL || code == MENU_ESCAPE){
  726.             break;
  727.         }else if (kernel_src.is_empty()){
  728.             xconf_error (MSG_U(E_KERNNEEDED,"You must specify a kernel file"));
  729.             nof = 0;
  730.         }else if (install != 1
  731.             && label.is_empty()){
  732.             xconf_error (MSG_U(E_LABELNEEDED,"You must specify a label"));
  733.             nof = 4;
  734.         }else if (install != 1
  735.             && getconffromlabel(label.get())!=NULL){
  736.             xconf_error (MSG_U(E_LABELEXIST,"The label is already used"));
  737.             nof = 4;
  738.         }else if (!file_exist(kernel_src.get())){
  739.             xconf_error (MSG_U(E_ENOENT,"File %s does not exist")
  740.                 ,kernel_src.get());
  741.             nof = 0;
  742.         }else if (kernel_dst.getlen() <= len_prefix
  743.             || kernel_dst.ncmp(prefix,len_prefix)!=0
  744.             || kernel_dst.get()[len_prefix] != '/'){
  745.             xconf_error (MSG_U(E_BADPATH,"Bad path, must be under %s/")
  746.                 ,prefix);
  747.             nof = 5;
  748.         }else if (validate_parm(newparm,def.root.is_empty())==-1){
  749.             nof = 7;
  750.         }else if (kernel_dst.cmp(kernel_src)==0
  751.             || !file_exist(kernel_dst.get())
  752.             || xconf_yesno(MSG_U(T_REPLACE,"Replace existing kernel file")
  753.                 ,MSG_U(I_REPLACE,"ok to overwrite it ?")
  754.                 ,help_lilo)==MENU_YES){
  755.             file_copy (kernel_src.get(),kernel_dst.get());
  756.             LILO_CONF *conf = confs.getitem(0);
  757.             if (install != 1 || conf == NULL){
  758.                 conf = new LILO_CONF;
  759.                 if (install == 0){
  760.                     confs.insert (0,conf);
  761.                 }else{
  762.                     confs.add (conf);
  763.                 }
  764.             }
  765.             conf->parm = newparm;
  766.             conf->label.setfrom(label);
  767.             conf->image.setfrom(kernel_dst.get()+len_prefix);
  768.             if (save() != -1) lilo_update();
  769.             break;
  770.         }
  771.     }
  772. }
  773.  
  774.  
  775. /*
  776.     Let the user install a new kernel he just compiled
  777. */
  778. void lilo_addcompil()
  779. {
  780.     static char std_image[]="/usr/src/linux/arch/i386/boot/zImage";
  781.     if (!file_exist (std_image)){
  782.         xconf_error (MSG_U(E_NOCOMPILED
  783.             ,"No kernel recently compiled available"));
  784.     }else{
  785.         FILE *fin = f_makefile.fopen ("r");
  786.         if (fin != NULL){
  787.             char name[30];
  788.             name[0] = '\0';
  789.             char buf[300];
  790.             int version = -1;
  791.             int patchlevel = -1;
  792.             int sublevel = -1;
  793.             while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
  794.                 char *pt = strchr (buf,'=');
  795.                 /* #Specification: lilo / /usr/src/linux/Makefile / assumption
  796.                     To help lilo admin set a proper name for his
  797.                     kernel file, we read /usr/src/linux/Makefile
  798.                     to grab PATCHLEVEL and SUBLEVEL. We assume
  799.                     that the Makefile has the following lines
  800.                     at the beginning.
  801.  
  802.                     #
  803.                     VERSION = x
  804.                     PATCHLEVEL = y
  805.                     SUBLEVEL = z
  806.                     #
  807.                     The order is not important. 
  808.                 */
  809.                 if (pt != NULL){
  810.                     pt = str_skip(pt+1);
  811.                     if (strncmp(buf,"VERSION",7)==0){
  812.                         version = atoi(pt);
  813.                     }else if (strncmp(buf,"PATCHLEVEL",10)==0){
  814.                         patchlevel = atoi(pt);
  815.                     }else if (strncmp(buf,"SUBLEVEL",8)==0){
  816.                         sublevel = atoi(pt);
  817.                     }
  818.                     if (version != -1
  819.                         && patchlevel != -1
  820.                         && sublevel != -1){
  821.                         sprintf (name,"kernel-%d.%d.%d"
  822.                             ,version,patchlevel,sublevel);
  823.                         break;
  824.                     }
  825.                 }
  826.             }
  827.             fclose (fin);    
  828.             LILO lilo;
  829.             lilo.addkernel(std_image,name);
  830.         }
  831.     }
  832. }
  833. /*
  834.     Let the user install a new kernel he got from anywhere
  835. */
  836. void lilo_addany()
  837. {
  838.     LILO lilo;
  839.     lilo.addkernel("","");
  840. }
  841.  
  842. /*
  843.     Let the user pick a different default boot configuration
  844. */
  845. PUBLIC void LILO::setdefault()
  846. {
  847.     DIALOG dia;
  848.     for (int i=0; i<confs.getnb(); i++){
  849.         LILO_CONF *c = confs.getitem(i);
  850.         dia.new_menuitem (c->label,c->image);
  851.     }
  852.     while (1){
  853.         int choice = 0;
  854.         MENU_STATUS code = dia.editmenu(
  855.             MSG_U(T_DEFKERN,"Default kernel configuration")
  856.             ,MSG_U(I_DEFKERN,"Pick the configuration which will become\n"
  857.              "the default LILO configuration\n"
  858.              "The first one is currently the default")
  859.             ,help_lilo
  860.             ,choice,0);
  861.         if (code == MENU_QUIT || code == MENU_ESCAPE){
  862.             break;
  863.         }else if (code == MENU_OK){
  864.             if (choice != 0){
  865.                 LILO_CONF *c = confs.getitem(choice);
  866.                 confs.remove (c);
  867.                 confs.insert (0,c);
  868.                 if (save() != -1) lilo_update();
  869.             }
  870.             break;
  871.         }
  872.     }
  873. }
  874.  
  875. void lilo_setdefault()
  876. {
  877.     LILO lilo;
  878.     lilo.setdefault();
  879. }
  880.  
  881.